package com.pulse.common.utils.sor;

import com.pulse.common.utils.sor.domain.Block;
import com.pulse.common.utils.sor.domain.CksumVo;
import com.pulse.common.utils.sor.domain.SorInfo;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Cksum {
    /**
     * 处理 Cksum 块
     *
     * @param fh      输入流
     * @param sorInfo 存储结果的对象
     * @return 状态字符串
     */
    public static String process(BufferedInputStream fh, SorInfo sorInfo) {
        final String bname = "Cksum";
        int hsize = bname.length() + 1; // 包括尾部的 '\0'
        String status = "nok";

        try {
            // 获取块的引用
            Block refBlock = sorInfo.getBlocks().getCksum();
            long startpos = (long) refBlock.getPos();
            fh.reset();
            fh.skip(startpos);  // 跳过块的起始位置
        } catch (Exception ex) {
            return status;
        }

        int format = sorInfo.getFormat();

        if (format == 2) {
            // 读取并验证头部
            byte[] buffer = new byte[hsize];
            try {
                fh.read(buffer, 0, hsize);
            } catch (IOException e) {
                return status;
            }
            String mystr = new String(buffer, StandardCharsets.US_ASCII);
            if (!mystr.equals(bname + "\0")) {
                return status;
            }
        }

        // 初始化 Cksum 字典
        sorInfo.setCksum(new CksumVo());
        CksumVo xref = sorInfo.getCksum();

        // 计算校验和
        int digest = calculateCRC16(fh);
        xref.setChecksumOurs((long)digest);

        // 读取文件中的校验和
        int csum = 0;
        try {
            csum = (int) Parts.getUInt(fh, 2);
        } catch (IOException e) {
            return status;
        }
        xref.setChecksum((long)csum);

        // 比较校验和
        xref.setMatch(digest == csum);

        status = "ok";
        return status;
    }


    /**
     * 计算文件的 CRC16 校验和
     *
     * @param inputStream 输入流
     * @return CRC16 校验和
     */
    public static int calculateCRC16(BufferedInputStream inputStream) {
        final int bufferSize = 4096; // 缓冲区大小
        byte[] buffer = new byte[bufferSize];
        int crc = 0xFFFF; // 初始值

        Crc16Ccitt crc16 = new Crc16Ccitt(0x1021, 0xFFFF, false, false, 0x0000);

        try {
            // 保存当前位置
            inputStream.mark(Integer.MAX_VALUE);
            inputStream.reset(); // 移动到文件开头

            int bytesRead;
            while ((bytesRead = inputStream.read(buffer, 0, bufferSize)) > 0) {
                crc16.update(buffer, 0, bytesRead);
            }

            // 恢复文件指针位置
            inputStream.reset();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return crc16.getChecksum();
    }
}
